package com.cn.sqlSession;

import com.cn.pojo.BoundSql;
import com.cn.pojo.Configuration;
import com.cn.pojo.MapperdStatement;
import com.cn.pojo.ParameterMapping;
import com.cn.utils.GenericTokenParser;
import com.cn.utils.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor {

    private Configuration configuration;

    public SimpleExecutor(){}

    public SimpleExecutor(Configuration configuration){
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> query(MapperdStatement mapperdStatement, Object... params) throws Exception {

        String sql = mapperdStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);

        // 3 获取预处理对象parementstatement
        PreparedStatement preparedStatement = prepareStatement(mapperdStatement, boundSql);
        System.out.println("sql:" + boundSql.getSqlText());


        // 处理参数
        paramterMapping(preparedStatement, mapperdStatement, boundSql, params);

        // 5 调用sql 封装结果集
        ResultSet resultSet = preparedStatement.executeQuery();

        // 处理返回
        List<E> list = resultMapping(mapperdStatement, resultSet);

        return list;
    }

    @Override
    public Integer update(MapperdStatement mapperdStatement, Object... params) throws Exception {
        String sql = mapperdStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);

        // 3 获取预处理对象parementstatement
        PreparedStatement preparedStatement = prepareStatement(mapperdStatement, boundSql);
        System.out.println("sql:" + boundSql.getSqlText());

        // 处理参数
        paramterMapping(preparedStatement, mapperdStatement, boundSql, params);

        preparedStatement.executeUpdate();
        int row = preparedStatement.getUpdateCount();

        return row;
    }

    @Override
    public Integer delete(MapperdStatement mapperdStatement, Object... params) throws Exception {
        String sql = mapperdStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);

        // 3 获取预处理对象parementstatement
        PreparedStatement preparedStatement = prepareStatement(mapperdStatement, boundSql);
        System.out.println("sql:" + boundSql.getSqlText());

        // 处理参数
        paramterMapping(preparedStatement, mapperdStatement, boundSql, params);

        preparedStatement.execute();
        int row = preparedStatement.getUpdateCount();
        return row;
    }

    @Override
    public Integer insert(MapperdStatement mapperdStatement, Object... params) throws Exception {
        String sql = mapperdStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);

        // 3 获取预处理对象parementstatement
        PreparedStatement preparedStatement = prepareStatement(mapperdStatement, boundSql);
        System.out.println("sql:" + boundSql.getSqlText());

        // 处理参数
        paramterMapping(preparedStatement, mapperdStatement, boundSql, params);

        preparedStatement.execute();
        int row = preparedStatement.getUpdateCount();


        return row;
    }

    private Class<?>  getClassType(String paramterType) {
        if(paramterType != null){
            try {
                Class<?> type = Class.forName(paramterType);
                return type;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private BoundSql getBoundSql(String sql) {
        // 解析sql  #{} -> ?  && 存储参数到parameterMappingTokenHandler.getParameterMappings()中
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        // 解析后的sql
        String parseSql = genericTokenParser.parse(sql);
        // sql 中的参数
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();

        return new BoundSql(parseSql, parameterMappings);
    }

    private PreparedStatement prepareStatement(MapperdStatement mapperdStatement, BoundSql boundSql) throws SQLException {
        // 1 获取数据库连接
        Connection connection = configuration.getDataSource().getConnection();

        // 2 获取sql语句
        //  现在是 select id,  username  from sys_user where id = #{mobile} and username = #{real_name}
        // 需要转成        select id,  username  from sys_user where id = ? and username = ?
        // 解析 #{}  并且 存储参数


        // 3 获取预处理对象parementstatement
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        System.out.println("sql:" + boundSql.getSqlText());

        return preparedStatement;

    }

    private PreparedStatement paramterMapping(PreparedStatement preparedStatement,
                                              MapperdStatement mapperdStatement,
                                              BoundSql boundSql,
                                              Object... params) throws Exception {
        String paramterType = mapperdStatement.getParamterType();
        Class<?> paramterClass = getClassType(paramterType);

        // 参数集合
        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();
        // 4 设置参数
        for (int i = 0; i < parameterMappingList.size(); i++) {
            // 获取 存储的对象
            String content = parameterMappingList.get(i).getProperty();
            // 获取 字段
            Field declaredField = paramterClass.getDeclaredField(content);
            // 设置暴力访问
            declaredField.setAccessible(true);

            // 获取传入的参数
            Object o = declaredField.get(params[0]);
            System.out.println("参数" + (i + 1) + ":" + o.toString());
            // 将参数设置到sql中
            preparedStatement.setObject(i + 1, o);
        }
        return preparedStatement;
    }

    private  <E> List<E> resultMapping(MapperdStatement mapperdStatement, ResultSet resultSet) throws Exception{
        String resultType = mapperdStatement.getResultType();
        Class<?> resultClass = getClassType(resultType);

        List<Object> list = new ArrayList<>();
        // 便利查询结果集
        while (resultSet.next()){
            // 结果集中的源数据
            ResultSetMetaData metaData = resultSet.getMetaData();
            // 实例化 返回对象
            E o = (E)resultClass.newInstance();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                // 字段名
                String columnName = metaData.getColumnName(i);
                // 字段值
                Object value = resultSet.getObject(columnName.toLowerCase());

                // 使用反射获类型， 根据数据库表和实体的对应关系，完成分装
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName.toLowerCase(), resultClass);
                Method method = propertyDescriptor.getWriteMethod();
                method.invoke(o, value);
            }
            list.add(o);
        }
        return (List<E>) list;
    }
}
